<?php

namespace app\organization\library;

use app\common\enums\OrganizationStateEnum;
use app\common\enums\OrganizationUserStateEnum;
use app\common\facade\Token;
use app\common\model\banxi\organization\Organization;
use app\common\model\banxi\organization\OrganizationUser as OrganizationUser;
use ba\Random;
use think\facade\Config;
use Throwable;

/**
 * 公共权限类（会员权限类）
 * @property int $id         会员ID
 * @property string $username   会员用户名
 * @property string $nickname   会员昵称
 * @property string $email      会员邮箱
 * @property string $mobile     会员手机号
 * @property string $password   密码密文
 * @property string $salt       密码盐
 */
class Auth extends \app\common\library\Auth
{

    public const TOKEN_TYPE = 'organization'; //机构

    /**
     * 机构ID
     * @var int
     */
    public string $organizationId;

    /**
     * 允许输出的字段
     * @var array
     */
    protected array $allowFields = [
        'id', 'del', 'account', 'isAdmin', 'roleId', 'roleKey', 'phone', 'state',
        'createBy', 'createTime', 'updateBy', 'updateTime', 'organizationId', 'realName'
    ];

    public function __construct(array $config = [])
    {
        parent::__construct(array_merge([
        ], $config));
        $this->setKeepTime((int)Config::get('buildadmin.teacher_token_keep_time'));
    }

    /**
     * 根据Token初始化会员登录态
     * @param $token
     * @return bool
     * @throws Throwable
     */
    public function init($token): bool
    {
        $tokenData = Token::get($token);
        if ($tokenData) {
            /**
             * 过期检查，过期则抛出 @see TokenExpirationException
             */
            Token::tokenExpirationCheck($tokenData);
            $userId = intval($tokenData['user_id']);
            //学员
            if ($tokenData['type'] == self::TOKEN_TYPE && $userId > 0) {
                $this->model = OrganizationUser::find(['id' => $userId]);
                if (!$this->model) {
                    $this->setError('Account not exist');
                    return false;
                }
                if ($this->model->state != OrganizationUserStateEnum::E1) {
                    $this->setError('Account disabled');
                    return false;
                }
                $this->token = $token;
                if (!$this->loginSuccessful()) {
                    return false;
                }
                return true;
            }
        }
        $this->reset();
        $this->setError('Token login failed');
        return false;
    }

    /**
     * 密码登录
     */
    public function loginPwd(string $username, string $password): array|bool
    {
        $this->model = OrganizationUser::getByAccount($username);
        if (!$this->model) {
            $this->setError('Account not exist');
            return false;
        }

        if (!verifyMd5Password($password, $this->model->password, $this->model->salt)) {
            $this->setError('Password is incorrect');
            return false;
        }
        // 清理 token
        $this->clearToken();
        if (!$this->loginSuccessful()) {
            return false;
        }
        return [
            'token' => $this->token,
        ];
    }

    /**
     * 忘记密码
     * @return bool
     */
    public function forgotPassword($newPassword): bool
    {
        $salt = createPasswordSalt();
        $this->model->salt = $salt;
        $this->model->password = createPassword($salt, $newPassword);
        $this->model->save();
        return true;
    }

    public function reUpdatePwd($rePwd, $newPassword): bool
    {
        if (!verifyMd5Password($rePwd, $this->model->password, $this->model->salt)) {
            $this->setError('Old password is incorrect');
            return false;
        }
        if (verifyMd5Password($newPassword, $this->model->password, $this->model->salt)) {
            $this->setError('New password cannot be the same as the original one');
            return false;
        }
        $this->forgotPassword($newPassword);
        $this->logout();
        return true;
    }

    public function loginSuccessful(): bool
    {
        if (!$this->model) {
            return false;
        }
        if (!$this->model->organizationId) {
            $this->setError('Account is not bound to an institution');
            return false;
        }
        $organization = Organization::where('id', $this->model->organizationId)->find();
        if (!$organization) {
            $this->setError('Organization not exist');
            return false;
        }
        if ($organization->status == OrganizationStateEnum::E3) {
            $this->setError('Organization disabled');
            return false;
        }
        try {
            $this->loginEd = true;
            $this->organizationId = $this->model->organizationId;
            if (!$this->token) {
                $this->setToken();
            }
        } catch (Throwable $e) {
            $this->setError($e->getMessage());
            return false;
        }
        return true;
    }

    /**
     * 获取机构信息 - 只输出允许输出的字段
     * @return array
     */
    public function getUserInfo(): array
    {
        if (!$this->model) return [];
        $info = $this->model->toArray();
        $info = array_intersect_key($info, array_flip($this->getAllowFields()));
        // $info['token'] = $this->getToken();
        $info['organizationBaseInfo'] = (new Organization)->getOrganizationBaseInfo($this->model->organizationId);
        return $info;
    }


    /**
     * 设置Token
     * @return bool
     */
    public function setToken(): bool
    {
        $this->token = Random::uuid();
        Token::set($this->token, self::TOKEN_TYPE, $this->model->id, $this->keepTime);
        return true;
    }

    /**
     * 清理Token
     * @return bool
     */
    public function clearToken(): bool
    {
        // 清理 token
        if (Config::get('buildadmin.client_sso')) {
            Token::clear(self::TOKEN_TYPE, $this->model->id);
            Token::clear(self::TOKEN_TYPE . '-refresh', $this->model->id);
        }
        return true;
    }

    /**
     * 退出登录
     * @return bool
     */
    public function logout(): bool
    {
        if (!$this->loginEd) {
            $this->setError('You are not logged in');
            return false;
        }
        return $this->reset();
    }

    /**
     * 属性重置（注销、登录失败、重新初始化等将单例数据销毁）
     */
    protected function reset(bool $deleteToken = true): bool
    {
        if ($deleteToken && $this->token) {
            Token::delete($this->token);
        }

        $this->token = '';
        $this->loginEd = false;
        $this->model = null;
        $this->refreshToken = '';
        $this->setError('');
        $this->setKeepTime((int)Config::get('buildadmin.teacher_token_keep_time'));
        return true;
    }
}